#ifndef IAC_First
#define IAC_First
#ifdef __GNUG__
#pragma interface
#endif

#include "SysEvtHandler.h"

class MemBuf;
class SeqCollection;
class IAC;

extern bool gIACDebug;
extern IAC *gRpc;

enum IACSendType {
	eBroadcast,
	ePoll,
	eSynchSend,
	eAsynchSend
};

//---- Request -----------------------------------------------------------------

class Request {
public:
	Request(int serial);
	Request(const char *buf, int len= -1);
	~Request();
	void AddPending();
	int RemovePending(char **result, int *retlen);
	void SetResult(int code, const char *result, int len= -1);
	friend void SetCurrentCommand(int ser, int code, const char *msg, int len);
public:
	int addr, code, len, serial;
	char *buf;
	Request *next;
};

//---- IACImpl -----------------------------------------------------------------

class IACImpl : public Object {
public:
	IACImpl(IAC *sc, const char *name= 0);
	virtual ~IACImpl();
	const char *GetName();
	int GetError();
	void SetName(const char*);
	virtual int Open(const char*);
	virtual int Close(const char*);
	virtual int LookupName(const char *nm, bool start);
	virtual int SendTo(int to, int ser, const char *buf, int len);
	virtual int Broadcast(int serial, const char *buf, int len);
	virtual int Poll(int serial, const char *buf, int len);
	virtual int SendReply(int to, int ser, int code, const char *buf, int len);
	virtual void SendUpError(int code);
	void SendUp(bool isreply, int from, int serial, const char *buf, int len= -1);
protected:
	char *name;
	IAC *sc;
	int errorcode;
};

inline const char *IACImpl::GetName()
	{ return name; }
inline int IACImpl::GetError()
	{ return errorcode; }

//---- IAC ---------------------------------------------------------------------

class IAC : public Object {
friend IACImpl;
public:
	MetaDef(IAC);
	IAC(const char *nm= 0);
	~IAC();

	void SetName(const char *name);
	const char *GetName();
	int LookupName(const char *nm, bool start= TRUE);

	// asynchronous
	int SendTo(int to, const char *req, const char *args, int l= -1);
	int SendTo(int to, const char *name, const char *req, const char *args,
								int l= -1);
	int SendReply(int to, int ser, int code, const char *args, int l= -1);

	// broadcasts
	int Broadcast(const char *name, const char *req, const char *args, int l= -1);
	int Broadcast(const char *req, const char *args, int l= -1);

	// synchronous
	int Talk(int client, const char *req, const char *args= 0, int len= -1,
						char **retbuf= 0, int *retlen= 0);
	int Talk(int client, const char *name, const char *req, const char *args= 0,
					int len= -1, char **retbuf= 0, int *retlen= 0);
	int Talk(const char *prog, const char *va_(fmt), ...);

protected:
	void Error(int code);
	int ISendTo(IACSendType st, int to, const char *req, const char *args,
					int l, char **retbuf= 0, int *retlen= 0);
	virtual void Dispatch2(int from, int ser, const char *msg, int len);
	virtual void Dispatch1(int from, int ser, const char *req, const char *args,
									int len);
	virtual int Dispatch(int from, const char *req, const char *args, int len,
						char *&retbuf, int &retlen);
protected:
	char *name;
	bool error;
	int serial, sid;
	IACImpl *rpc;
};

//---- Service -----------------------------------------------------------------

class Service : public SysEvtHandler {
public:
	MetaDef(Service);
	Service(const char *name);
	~Service();
	const char *GetName();
	int Talk(int to, const char *request);
	int SendTo(int to, const char *request);
	int Broadcast(const char *request);
	void ExtCommand(int from, int serial, IAC *sc,
			const char *req, const char *args, int arglen);

protected:
	virtual int Dispatch(int from, const char *req, IStream &is, OStream &os);
	void InspectorId(char *buf, int bufSize);

protected:
	char *name;
	MemBuf *omb, *imb;
	OStream *os;
	IStream *is;
};

inline const char *Service::GetName()
	{ return name; }

#endif

